#include "stdafx.h"

#include "Window.h"
#include <stdio.h>
#include <afxcmn.h>
#include "Render\Render.h"
#include "Common\Viewer.h"
#include "..\CommLib\CommStructs.h"
#include "..\Global\globaldef.h"

CWindow::CMFCWindow* CWindow::g_ApplicationWindow = NULL; 
CWindow::CMFCInst CWindow::g_ApplicationInstance;
const std::string CWindow::g_WindowTitle = std::string("Viewer");
UINT CWindow::g_Keyboard[256] = {0};
void (*CWindow::g_pKeyboardEventHandler)(UINT *pKeyboardState) = NULL;
void (*CWindow::g_pMouseEventHandler)(const int dxMouse, const int dyMouse, const int leftButton, const int rightButton) = NULL;

CWindow::CMFCChildWindow::CMFCChildWindow() {

}

CWindow::CMFCChildWindow::~CMFCChildWindow() {

}

BEGIN_MESSAGE_MAP(CWindow::CMFCChildWindow, CWnd)
	ON_WM_PAINT()
	ON_WM_ERASEBKGND()
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONDOWN()
	ON_WM_KEYDOWN()
	ON_WM_KEYUP()
END_MESSAGE_MAP()

void CWindow::CMFCChildWindow::OnToolbarDropDown(NMHDR* pnmtb, LRESULT *plr) {

	switch (pnmtb->code)
	{
	case TBN_DROPDOWN:
		CMenu menu;
		menu.LoadMenu(IDR_MENU3);
		CMenu* pPopup = menu.GetSubMenu(0);
		ASSERT(pPopup);
		
		CRect rc;
		
		SendMessage(TB_GETRECT, IDC_TBBUTTON2, (LPARAM)&rc);
		pPopup->TrackPopupMenu( TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL,
			rc.left, rc.bottom, this, &rc);
		break;
	}
}

BOOL CWindow::CMFCChildWindow::PreCreateWindow(CREATESTRUCT& cs) {

	if (!CWnd::PreCreateWindow(cs))
		return FALSE;

	cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS, 
		::LoadCursor(NULL, IDC_ARROW), reinterpret_cast<HBRUSH>(COLOR_WINDOW+1), NULL);

	return TRUE;
}

BOOL CWindow::CMFCChildWindow::OnEraseBkgnd(CDC* pDC) {

	return true;
}

void CWindow::CMFCChildWindow::OnPaint()  {

	CWnd::OnPaint();
	CViewer::OnRenderFrame();
}

CWindow::CMFCWindow::CMFCWindow() {

	u_int wndWidth = 800;
	u_int wndHeight = 600;	
	RECT wndRect = {(GetSystemMetrics(SM_CXSCREEN) - wndWidth) / 2, 
					(GetSystemMetrics(SM_CYSCREEN) - wndHeight) / 2, 
					(GetSystemMetrics(SM_CXSCREEN) + wndWidth) / 2,
					(GetSystemMetrics(SM_CYSCREEN) + wndHeight) / 2};

	wndRect.left -= GetSystemMetrics(SM_CXSCREEN) / 4;
	wndRect.right -= GetSystemMetrics(SM_CXSCREEN) / 4;

	Create(NULL,CWindow::g_WindowTitle.c_str(), WS_POPUPWINDOW | WS_VISIBLE | WS_DLGFRAME, wndRect);
}

INT CWindow::CMFCWindow::OnCreate(LPCREATESTRUCT lpCreateStruct) {

	if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
		return FALSE;

	// create a view to occupy the client area of the frame
	if (!m_wndView.Create(NULL, NULL, WS_CHILD | WS_VISIBLE,
		CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, NULL))
	{
		TRACE0("Failed to create view window\n");
		return -1;
	}

	ShowCursor(false);
	return TRUE;
}

void CWindow::CMFCChildWindow::GetClientCursor(CPoint* pOut, CPoint point) {

	RECT windowClientArea;
	CWindow::GetClientRectangle(&windowClientArea);

	CPoint cursor;
	cursor.x = (windowClientArea.right - windowClientArea.left) / 2;
	cursor.y = (windowClientArea.bottom - windowClientArea.top) / 2;

	CPoint displacement = point - cursor;
	if((displacement.x * displacement.x) + (displacement.y * displacement.y) > 0)
	{
		POINT cur = {cursor.x,cursor.y};
		ClientToScreen(&cur);
		pOut->x = displacement.x;
		pOut->y = displacement.y;
	}
	else {
	
		pOut->x = 
		pOut->y = 0;
	}
}

void CWindow::CMFCChildWindow::OnLButtonDown(UINT nFlags, CPoint point) {
	
	if(!(CWindow::IsWindowMinimized())) {

		if(g_pMouseEventHandler) {
	
			CPoint clientPosition;
			GetClientCursor(&clientPosition, point);
			g_pMouseEventHandler(clientPosition.x,clientPosition.y, 1, 0);
		}
	}
}

void CWindow::CMFCChildWindow::OnMouseMove(UINT nFlags, CPoint point) {


	if(!(CWindow::IsWindowMinimized())) {

		if(g_pMouseEventHandler) {
				
			CPoint clientPosition;
			GetClientCursor(&clientPosition, point);
			g_pMouseEventHandler(clientPosition.x,clientPosition.y, 0, 0);
		}
	}
}

BOOL CWindow::CMFCWindow::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) {

	if (m_wndView.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
		return TRUE;

	return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}

void CWindow::CMFCWindow::OnSetFocus(CWnd* /*pOldWnd*/) {

	m_wndView.SetFocus();
}

BEGIN_MESSAGE_MAP( CWindow::CMFCWindow, CFrameWnd)
	ON_WM_CREATE()
	ON_WM_SETFOCUS()
END_MESSAGE_MAP()

void CWindow::CMFCChildWindow::OnKeyDown(UINT nChar, UINT nRepCount, UINT nFlags) {

	OnKeyEvent(nChar, nFlags, true);
}

void CWindow::CMFCChildWindow::OnKeyUp(UINT nChar, UINT nRepCount, UINT nFlags) {

	OnKeyEvent(nChar, nFlags, false);
}

void CWindow::CMFCChildWindow::OnKeyEvent(UINT nChar, UINT nFlags, bool isDown) {
	
	if(!CWindow::IsWindowMinimized()) {
	
		if(g_pKeyboardEventHandler) {

			const bool beingReleased	= nFlags & (0x4000);
			const bool previouslyDown	= nFlags & (0x2000);
			
			g_Keyboard[nChar] = isDown ? KEY_DOWN : KEY_UP;

			if(!previouslyDown)
				g_Keyboard[nChar] |= KEY_ON_PRESSED;
			if(previouslyDown)
				g_Keyboard[nChar] |= KEY_ON_RELEASE;
			
			g_pKeyboardEventHandler(g_Keyboard);
		}
	}
}

BOOL CWindow::CMFCInst::InitInstance() {

	VTRY {

		CWinApp::InitInstance();

		if(FALSE == AllocConsole())
			VTHROW_INTERNALERROR("Failed to get console.");

		if(!freopen("con:","w",stdout))
			VTHROW_INTERNALERROR("Failed to reopen stdout stream.");
		
		CWindow::g_ApplicationWindow = new CWindow::CMFCWindow();
		if(!CWindow::g_ApplicationWindow)
			VTHROW_INTERNALERROR("Failed to create window.");

		g_pKeyboardEventHandler = &CViewer::OnKeyboardEvent;
		g_pMouseEventHandler = &CViewer::OnMouseEvent;


		m_pMainWnd = CWindow::g_ApplicationWindow;
		m_pMainWnd->ShowWindow(SW_NORMAL);
		CViewer::OnInitalize();
		

		return TRUE;

	}VCATCHONLY;

	CViewer::OnShutdown();
	fclose(stdout);
	FreeConsole();
	g_pKeyboardEventHandler = NULL;
	g_pMouseEventHandler = NULL;

	return FALSE;
}

BOOL CWindow::CMFCInst::OnIdle(LONG lCount) {

	CWinApp::OnIdle(lCount);

	Sleep(15);
	CWindow::g_ApplicationWindow->m_wndView.Invalidate();

	CViewer::OnUpdate();
	return TRUE;
}


INT CWindow::CMFCInst::ExitInstance() {

	CViewer::OnShutdown();

	fclose(stdout);
	FreeConsole();
	g_pKeyboardEventHandler = NULL;

	return TRUE;
}

void CWindow::Close() {
	
	if(IDYES == MessageBox(CWindow::GetHandle(), "Are you sure you want to quit?", CWindow::g_WindowTitle.c_str(), MB_ICONQUESTION | MB_YESNO))
		CWindow::g_ApplicationWindow->CloseWindow();
}

void CWindow::Move() {

	CWindow::g_ApplicationWindow->SendMessage(WM_SYSCOMMAND, SC_MOVE, 0);
}

void CWindow::GetClientRectangle(RECT* pRect) {
	
	if(pRect && CWindow::g_ApplicationWindow) {
		CWindow::g_ApplicationWindow->m_wndView.GetClientRect(pRect);
	}
}

void CWindow::CenterMouse() {
	
	CPoint point;
	GetCursorPos(&point);

	ScreenToClient(CWindow::GetHandle(), &point);
	
	RECT windowClientArea;
	CWindow::GetClientRectangle(&windowClientArea);

	CPoint center;
	center.x = (windowClientArea.right - windowClientArea.left) / 2;
	center.y = (windowClientArea.bottom - windowClientArea.top) / 2;

	CPoint displacement = point - center;
	if((displacement.x * displacement.x) + (displacement.y * displacement.y) > 10)
	{
		ClientToScreen(CWindow::GetHandle(), &center);
		//POINT cur = {cursor.x,cursor.y};
		//ClientToScreen(&cur);

		SetCursorPos(center.x,center.y);
	}
	
}
POINT CWindow::GetMousePosition() {

	POINT cursor;
	if(CWindow::GetHandle() && GetCursorPos(&cursor)) {
		ScreenToClient(CWindow::GetHandle(), &cursor);
	}
	return cursor;
}

HWND CWindow::GetHandle() {

	return CWindow::g_ApplicationWindow ? CWindow::g_ApplicationWindow->m_wndView.GetSafeHwnd() : NULL;
}

BOOL CWindow::IsWindowMinimized() {

	BOOL isIconic = CWindow::g_ApplicationWindow ? CWindow::g_ApplicationWindow->IsIconic() : FALSE;
	BOOL isNotFocus = CWindow::GetHandle() != GetFocus();
	return isIconic || isNotFocus;
}
